Skip to content

fix(distill): detach bg pipeline with setsid so it survives session teardown#322

Merged
seoseo-ai merged 1 commit into
mainfrom
fix/distill-setsid-detach
Jul 7, 2026
Merged

fix(distill): detach bg pipeline with setsid so it survives session teardown#322
seoseo-ai merged 1 commit into
mainfrom
fix/distill-setsid-detach

Conversation

@jinon86

@jinon86 jinon86 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

What

distill.sh의 bg 파이프라인 spawn을 disowned subshell → setsid self re-entry(신규 세션)로 교체. setsid 미가용 환경은 기존 subshell fallback 유지.

Why

2026-07-07 fleet 점검에서 gwakga/nosuk의 sessionend distill이 spawned bg 로그 후 done/skip/error 없이 무로그 사망 (distill-last.json stale). 원인: ssh 유지보수 세션 teardown이 프로세스 그룹째 kill → disown/nohup은 SIGHUP만 방어, group-kill 미방어.

How

  • 파이프라인 본문을 run_bg_pipeline()로 추출 (CLAUDE_DISTILL_* env 계약은 기존과 동일)
  • CLAUDE_DISTILL_BG=1 setsid bash distill.sh <trigger>로 재진입 — 재진입 체크는 hook-input 파싱 이전, INFLIGHT는 파이프라인이 스스로 export하므로 recursion guard 유지
  • 로그 라인에 mode=setsid|subshell 추가 (기존 spawned bg grep 계약 유지)

Evidence

  • claude/hooks/distill-scope.test.sh: 18/18 PASS
  • PG-kill 시뮬레이션: hook 종료 직후 kill -KILL -$$ (stub extract sleep 2s 중) → 파이프라인 완주(dry-run skipping ... elapsed_s=2). 구 코드 시나리오 재현으로 silent death 확인됨.

Wiki: LOG-1509 후속 (memory-pipeline fleet 점검)

🤖 Generated with Claude Code

…eardown

The distill bg pipeline was spawned as a disowned subshell, which stays in
the hook's process group/session. When the parent Claude session is torn
down as a group (ssh-driven maintenance sessions, CLI teardown), the
pipeline is killed before it can log anything — observed fleet-wide on
2026-07-07: gwakga/nosuk sessionend runs ended at "spawned bg" with no
done/skip/error line and stale distill-last.json. disown/nohup only guard
against SIGHUP, not group-targeted kills.

Fix: extract the pipeline body into run_bg_pipeline() and re-invoke the
script via `setsid bash distill.sh` with CLAUDE_DISTILL_BG=1 (new session,
immune to group teardown). Where setsid is unavailable, fall back to the
legacy disowned subshell. Inputs flow through the existing CLAUDE_DISTILL_*
env contract in both modes; the bg re-entry is checked before any hook-input
parsing and does not set INFLIGHT itself, so the recursion guard still
protects the nested `claude -p` session.

Evidence:
- claude/hooks/distill-scope.test.sh: 18/18 PASS
- PG-kill simulation: spawn hook via setsid, `kill -KILL -$$` immediately
  after hook exit while stub extract sleeps 2s -> pipeline completes
  ("dry-run skipping ... elapsed_s=2"). Same scenario reproduced the
  silent death with the old spawn.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jinon86 jinon86 requested a review from seoseo-ai as a code owner July 7, 2026 16:37

@seoseo-ai seoseo-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — distill bg pipeline setsid detach. Evidence: distill-scope.test.sh 18/18 PASS + PG-kill simulation survival (pipeline completes while parent group SIGKILLed mid-extract). Recursion-guard ordering (BG re-entry before INFLIGHT self-export) verified in review.

@seoseo-ai seoseo-ai merged commit 8747f8d into main Jul 7, 2026
7 checks passed
@seoseo-ai seoseo-ai deleted the fix/distill-setsid-detach branch July 7, 2026 16:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants